﻿Imports System.Drawing
Imports Microsoft.Office.Interop
Imports System.IO

Public Class Gestor

#Region "Elías Baldioceda"
    ''' <summary>
    ''' Registrar usuario.
    ''' </summary>
    ''' <param name="p_tipoId">Tipo de identificación.</param>
    ''' <param name="p_identificacion">Identificación.</param>
    ''' <param name="p_nombre">Nombre.</param>
    ''' <param name="p_primerApellido">Primero apellido.</param>
    ''' <param name="p_segundoApellido">Segundo apellido.</param>
    ''' <param name="p_genero">Género.</param>
    ''' <param name="p_fechaNacimiento">Fecha de nacimiento.</param>
    ''' <param name="p_correo">Correo electrónico.</param>
    ''' <param name="p_telefono">Teléfono.</param>
    ''' <param name="p_rol">Código del rol.</param>
    ''' <param name="p_foto">Foto.</param>
    ''' <param name="p_curriculo">Currículo.</param>
    ''' <param name="p_nombreUsuario">Nombre de usuario.</param>
    ''' <param name="p_puesto">Código del puesto.</param>
    ''' <returns>Contraseña del usuario.</returns>
    ''' <remarks>Creado por: Elías Baldioceda, Fecha: 14/06/2010, Modificado: 15/06/2010</remarks>
    Public Shared Function usuarioRegistrar(ByVal p_tipoId As String, ByVal p_identificacion As String, ByVal p_nombre As String, _
                                ByVal p_primerApellido As String, ByVal p_segundoApellido As String, ByVal p_genero As String, _
                                ByVal p_fechaNacimiento As Date, ByVal p_correo As String, ByVal p_telefono As String, _
                                ByVal p_rol As Integer, ByVal p_foto As Bitmap, ByVal p_curriculo As String, _
                                ByVal p_nombreUsuario As String, ByVal p_puesto As Integer) As String
        Dim contrasenna As String
        Dim contrasennaEncriptada As String
        Dim genero As Boolean
        Dim foto() As Byte
        Dim curriculo() As Byte

        ' Comprobar si es empleado común no puede ser ni admin ni gerente general.
        If p_rol = 3 Then
            If p_puesto = 1 Then
                Throw New Exception("Un empleado común no puede ser gerente general.")
            ElseIf p_puesto = 2 Then
                Throw New Exception("Un empleado común no puede ser de recursos humanos.")
            End If
        End If

        ' Comprobar si es gerente general y si ya hay uno.
        If p_rol = 2 Then
            If MultiUsuario.hayGerenteGeneral() Then
                Throw New Exception("Ya hay un gerente general en el sistema.")
            End If
        End If

        ' Comprobar nombre de usuario
        If MultiUsuario.existeNombreUsuario(p_nombreUsuario) Then
            Throw New Exception("El nombre de usuario ya está en uso.")
        End If

        ' Generar contraseña
        contrasenna = New Random().Next(10000, 1000000)
        contrasennaEncriptada = Utils.encriptar(contrasenna)

        ' Cambiar género a Boolean
        genero = p_genero Is "Femenino"

        ' Transformar foto a bytes
        foto = Utils.object2Byte(p_foto)

        ' Transformar curriculo a bytes
        curriculo = Utils.object2Byte(p_curriculo)

        MultiUsuario.registrar(p_tipoId, p_identificacion, p_nombre, p_primerApellido, p_segundoApellido, _
                               p_nombreUsuario, contrasennaEncriptada, genero, p_fechaNacimiento, p_correo, p_telefono, _
                               p_rol, foto, curriculo, p_puesto)

        Return contrasenna
    End Function

    ''' <summary>
    ''' Modifica un usuario.
    ''' </summary>
    ''' <param name="p_tipoId">Tipo de identificación.</param>
    ''' <param name="p_identificacion">Identificación.</param>
    ''' <param name="p_nombre">Nombre.</param>
    ''' <param name="p_primerApellido">Primero apellido.</param>
    ''' <param name="p_segundoApellido">Segundo apellido.</param>
    ''' <param name="p_genero">Género.</param>
    ''' <param name="p_fechaNacimiento">Fecha de nacimiento.</param>
    ''' <param name="p_correo">Correo electrónico.</param>
    ''' <param name="p_telefono">Teléfono.</param>
    ''' <param name="p_rol">Código del rol.</param>
    ''' <param name="p_foto">Foto.</param>
    ''' <remarks>Creado por: Elías Baldioceda, Fecha: 20/06/2010, Modificado: 20/06/2010</remarks>
    Public Shared Sub usuarioModificar(ByVal p_tipoId As String, ByVal p_identificacion As String, ByVal p_nombre As String, _
                                ByVal p_primerApellido As String, ByVal p_segundoApellido As String, ByVal p_genero As String, _
                                ByVal p_fechaNacimiento As Date, ByVal p_correo As String, ByVal p_telefono As String, _
                                ByVal p_rol As Integer, ByVal p_foto As Bitmap)
        Dim genero As Boolean
        Dim foto() As Byte
        Dim usuario As Usuario

        usuario = MultiUsuario.buscar(p_identificacion)

        ' Si es administrador y sólo queda uno, no debe permitir cambiarle el rol
        If usuario.rol = 1 And p_rol <> 1 Then
            If Not MultiUsuario.puedeEliminarAdmin() Then
                Throw New Exception("No puede cambiar el rol del último administrador.")
            End If
        End If

        ' Comprobar si es gerente general y si ya hay uno
        If p_rol = 2 Then
            If MultiUsuario.hayGerenteGeneral() Then
                Throw New Exception("Ya hay un gerente general en el sistema.")
            End If
        End If

        ' Cambiar género a Boolean
        genero = p_genero Is "Femenino"

        ' Transformar foto a bytes
        foto = Utils.object2Byte(p_foto)
		
		' Asigna el puesto según el rol
        If p_rol = 1 Then
            modificarPuestoAEmpleado(p_identificacion, 2)
        ElseIf p_rol = 2 Then
            modificarPuestoAEmpleado(p_identificacion, 1)
        End If

        MultiUsuario.modificar(p_tipoId, p_identificacion, p_nombre, p_primerApellido, p_segundoApellido, _
                               genero, p_fechaNacimiento, p_correo, p_telefono, p_rol, foto)
    End Sub

    ''' <summary>
    ''' Busca un usuario.
    ''' </summary>
    ''' <param name="p_identificacion">Número de identificación.</param>
    ''' <returns>Datos de un usuario.</returns>
    ''' <remarks>Creado por: Elías Baldioceda, Fecha: 20/06/2010, Modificado: 20/06/2010</remarks>
    Public Shared Function usuarioBuscar(ByVal p_identificacion As String) As Hashtable
        Dim usuario As Usuario

        usuario = MultiUsuario.buscar(p_identificacion)

        If usuario Is Nothing Then
            Throw New Exception("El usuario no existe.")
        End If

        Return usuario.toHashtable
    End Function

    ''' <summary>
    ''' Busca los usuarios.
    ''' </summary>
    ''' <param name="p_identificacion">Número de identificación.</param>
    ''' <param name="p_nombre">Nombre y/o apellidos.</param>
    ''' <returns>Lista de datos de usuarios.</returns>
    ''' <remarks>Creado por: Elías Baldioceda, Fecha: 19/06/2010, Modificado: 19/06/2010</remarks>
    Public Shared Function usuarioBuscar(ByVal p_identificacion As String, ByVal p_nombre As String) As List(Of Hashtable)
        Dim usuarios As New List(Of Hashtable)
        Dim usuarioTemp As Hashtable
        Dim usuariosObj As List(Of Usuario)

        usuariosObj = MultiUsuario.buscar(p_identificacion, p_nombre)

        For Each usuario As Usuario In usuariosObj
            Dim nombreDepartamento As String = Nothing

            ' Carga el departamento del puesto del usuario si es que tiene
            If Not usuario.puesto Is Nothing Then
                Dim departamento As Departamento = Nothing
                departamento = MultiDepartamento.buscarPorPuesto(usuario.puesto.codigo)
                nombreDepartamento = departamento.nombre
            End If

            usuarioTemp = usuario.toHashtable ' Lo pasa a Hashtable
            usuarioTemp.Add("departamento", nombreDepartamento) ' Agrega el departamento al Hashtable

            usuarios.Add(usuarioTemp)
        Next

        Return usuarios
    End Function

    ''' <summary>
    ''' Obtiene la foto del usuario.
    ''' </summary>
    ''' <param name="p_identificacion">Número de identificación.</param>
    ''' <returns>Foto del usuario.</returns>
    ''' <remarks>Creado por: Elías Baldioceda, Fecha: 20/06/2010, Modificado: 20/06/2010</remarks>
    Public Shared Function usuarioObtenerFoto(ByVal p_identificacion As String) As Bitmap
        Return MultiUsuario.obtenerFoto(p_identificacion)
    End Function

    ''' <summary>
    ''' Obtiene los datos del usuario actual.
    ''' </summary>
    ''' <returns>Datos del usuario.</returns>
    ''' <remarks>Creado por: Elías Baldioceda, Fecha: 20/06/2010, Modificado: 20/06/2010</remarks>
    Public Shared Function usuarioActual() As Hashtable
        Return g_usuario.toHashtable
    End Function

    ''' <summary>
    ''' Elimina un usuario.
    ''' </summary>
    ''' <param name="p_identificacion">Número de identificación.</param>
    ''' <remarks>Creado por: Elías Baldioceda, Fecha: 20/06/2010, Modificado: 20/06/2010</remarks>
    Public Shared Sub usuarioEliminar(ByVal p_identificacion As String)
        Dim usuario As Usuario

        usuario = MultiUsuario.buscar(p_identificacion)

        ' Si es administrador y sólo queda uno, no debe eliminarlo
        If usuario.rol = 1 Then
            If Not MultiUsuario.puedeEliminarAdmin() Then
                Throw New Exception("No puede eliminar el último administrador.")
            End If
        End If

        ' Si es director de departamento que no permita eliminarlo
        If MultiUsuario.esDirectorDepartamento(p_identificacion) Then
            Throw New Exception("No puede eliminar un director de departamento.")
        End If

        MultiUsuario.eliminar(p_identificacion)
    End Sub

    ''' <summary>
    ''' Cambia el estado de un usuario.
    ''' </summary>
    ''' <param name="p_identificacion">Número de identificación.</param>
    ''' <param name="p_estado">Estado.</param>
    ''' <remarks>Creado por: Elías Baldioceda, Fecha: 20/06/2010, Modificado: 20/06/2010</remarks>
    Public Shared Sub usuarioCambiarEstado(ByVal p_identificacion As String, ByVal p_estado As Estado)
        MultiUsuario.cambiarEstado(p_identificacion, p_estado)
    End Sub

    ''' <summary>
    ''' Devuelve el desglose de la liquidación de un empleado.
    ''' </summary>
    ''' <param name="p_identificacion">Número de identificación.</param>
    ''' <returns>Datos de la liquidación.</returns>
    ''' <remarks>Creado por: Elías Baldioceda, Fecha: 22/06/2010, Modificado: 28/06/2010</remarks>
    Public Shared Function usuarioLiquidacion(ByVal p_identificacion As String) As Hashtable
        Dim liquidacion As New Hashtable
        Dim usuario As Usuario
        Dim salarios As List(Of Salario)

        Dim vacaciones As Double = 0
        Dim preaviso As Double = 0
        Dim cesantia As Double = 0
        Dim aguinaldo As Double = 0

        Dim vacacionesDisponibles As Integer = 0
        Dim salarioPorDia As Double = 0
        Dim annosLaborados As Integer = 0

        usuario = MultiUsuario.buscar(p_identificacion)
        salarios = MultiSalario.buscar(p_identificacion)

        ' TODO: Optimizar el cálculo de salario por día (de un año) y asegurarme que está bien.
        Dim i As Integer = 0
        For Each salario As Salario In salarios
            salarioPorDia += salario.salarioNetoS
            i += 1

            If i >= 12 Then
                Exit For ' WTF?!. Sí, luego lo mejoro xDDD
            End If
        Next

        If salarios.Count > 0 Then
            salarioPorDia = (salarioPorDia / salarios.Count) / 30
        End If

        If (Date.Now.Year - usuario.fechaIngreso.Year) = 0 Then
            vacacionesDisponibles = Date.Now.Month - usuario.fechaIngreso.Month ' Cuántos meses lleva trabajando.
            vacacionesDisponibles += 1 ' Basta con estar en el mes, no tenerlo terminado.
        Else
            vacacionesDisponibles = Date.Now.Month ' 1 día por mes.
        End If

        vacacionesDisponibles -= usuario.vacaciones ' Vacaciones que puede utilizar menos las ya utilizadas.

        annosLaborados = Date.Now.Year - usuario.fechaIngreso.Year

        ' Calcular vacaciones
        vacaciones = salarioPorDia * vacacionesDisponibles

        ' Calcular preaviso
        preaviso = salarioPorDia * 30 ' Los 30 días de preaviso.

        ' Calcular cesantia
        Select Case annosLaborados
            Case 0
                Dim mesesLaborados As Integer

                mesesLaborados = Date.Now.Month - usuario.fechaIngreso.Month

                If mesesLaborados > 6 Then
                    cesantia = 14 * salarioPorDia
                ElseIf mesesLaborados > 3 Then
                    cesantia = 7 * salarioPorDia
                End If
            Case 1
                cesantia = (19.5 * annosLaborados) * salarioPorDia
            Case 2
                cesantia = (20 * annosLaborados) * salarioPorDia
            Case 3
                cesantia = (20.5 * annosLaborados) * salarioPorDia
            Case 4
                cesantia = (21 * annosLaborados) * salarioPorDia
            Case 5
                cesantia = (21.24 * annosLaborados) * salarioPorDia
            Case 6
                cesantia = (21.5 * annosLaborados) * salarioPorDia
            Case 7, 8, 9
                cesantia = (22 * annosLaborados) * salarioPorDia
            Case 10
                cesantia = (21.5 * annosLaborados) * salarioPorDia
            Case 11
                cesantia = (21 * annosLaborados) * salarioPorDia
            Case 12
                cesantia = (20.5 * annosLaborados) * salarioPorDia
            Case Else ' 13 años o más.
                cesantia = (20 * annosLaborados) * salarioPorDia
        End Select

        ' TODO: Calcular aguinaldo
        aguinaldo = 30 * salarioPorDia ' Se paga un mes.

        liquidacion("vacaciones") = vacaciones
        liquidacion("preaviso") = preaviso
        liquidacion("cesantia") = cesantia
        liquidacion("aguinaldo") = aguinaldo
        liquidacion("total") = vacaciones + preaviso + cesantia + aguinaldo

        Return liquidacion
    End Function

    ''' <summary>
    ''' Liquida un empleado.
    ''' </summary>
    ''' <param name="p_identificacion">Número de identificación.</param>
    ''' <remarks>Creado por: Elías Baldioceda, Fecha: 22/06/2010, Modificado: 22/06/2010</remarks>
    Public Shared Sub usuarioLiquidar(ByVal p_identificacion As String)
        Dim liquidacion As Hashtable
        Dim usuario As Usuario

        usuario = MultiUsuario.buscar(p_identificacion)

        ' Si es administrador y sólo queda uno, no debe eliminarlo
        If usuario.rol = 1 Then
            If Not MultiUsuario.puedeEliminarAdmin() Then
                Throw New Exception("No puede liquidar el último administrador.")
            End If
        End If

        ' Si es director de departamento que no permita liquidarlo
        If MultiUsuario.esDirectorDepartamento(p_identificacion) Then
            Throw New Exception("No puede liquidar un director de departamento.")
        End If

        liquidacion = usuarioLiquidacion(p_identificacion)

        MultiUsuario.liquidar(p_identificacion, liquidacion("vacaciones"), liquidacion("preaviso"), _
                              liquidacion("cesantia"), liquidacion("aguinaldo"))
        MultiUsuario.eliminar(p_identificacion)
    End Sub

    ''' <summary>
    ''' Modifica las vacaciones de un empleado.
    ''' </summary>
    ''' <param name="p_identificacion">Número de identificación.</param>
    ''' <param name="p_vacaciones">Número de vacaciones utilizadas.</param>
    ''' <remarks>Creado por: Elías Baldioceda, Fecha: 23/06/2010, Modificado: 23/06/2010</remarks>
    Public Shared Sub usuarioModificarVacaciones(ByVal p_identificacion As String, ByVal p_vacaciones As Integer)
        Dim usuario As Usuario
        Dim vacacionesDisponibles As Integer

        usuario = MultiUsuario.buscar(p_identificacion)

        If (Date.Now.Year - usuario.fechaIngreso.Year) = 0 Then
            vacacionesDisponibles = Date.Now.Month - usuario.fechaIngreso.Month ' Cuántos meses lleva trabajando.
            vacacionesDisponibles += 1 ' Basta con estar en el mes, no tenerlo terminado.
        Else
            vacacionesDisponibles = Date.Now.Month ' 1 día por mes.
        End If

        If p_vacaciones > vacacionesDisponibles Then
            Throw New Exception("Tiene " & vacacionesDisponibles & " día(s) de vacacion(es) disponible(s) hasta ahora. No se puede sobrepasar.")
        End If

        MultiUsuario.modificarVacaciones(p_identificacion, p_vacaciones)
    End Sub

    ''' <summary>
    ''' Verifica si el usuario tiene el permiso indicado.
    ''' </summary>
    ''' <param name="p_identificacion">Número de identificación.</param>
    ''' <param name="p_permiso">Código del permiso.</param>
    ''' <returns>Si el usuario tiene el permiso.</returns>
    ''' <remarks>Creado por: Elías Baldioceda, Fecha: 27/04/2010, Modificado: 27/04/2010</remarks>
    Public Shared Function usuarioTienePermiso(ByVal p_identificacion As String, ByVal p_permiso As Integer) As Boolean
        Dim tiene As Boolean = False

        If p_identificacion <> Nothing Then
            tiene = MultiUsuario.tienePermiso(p_identificacion, p_permiso)
        End If

        Return tiene
    End Function

    ''' <summary>
    ''' Obtiene la nota promedio de la evaluación del usuario.
    ''' </summary>
    ''' <param name="p_identificacion">Número de indentificación.</param>
    ''' <returns>Nota promedio.</returns>
    ''' <remarks>Creado por: Elías Baldioceda, Fecha: 20/07/2010, Modificado: 20/07/2010</remarks>
    Public Shared Function usuarioNotaPromedio(ByVal p_identificacion As String) As Double
        Dim notas As List(Of Double)
        Dim notaPromedio As Double = 0

        notas = MultiUsuario.obtenerNotaPromedio(p_identificacion)
        notas.Capacity = 5

        For i As Integer = 0 To (notas.Count - 1)
            notaPromedio += notas.Item(i)
        Next

        notaPromedio /= 5

        Return notaPromedio
    End Function

    ''' <summary>
    ''' Identifica si el usuario existe.
    ''' </summary>
    ''' <param name="p_nombreUsuario">Nombre de usuario.</param>
    ''' <param name="p_contrasenna">Contraseña.</param>
    ''' <returns>Datos del usuario identificado.</returns>
    ''' <remarks>Creado por: Elías Baldioceda, Fecha: 19/06/2010, Modificado: 19/06/2010</remarks>
    Public Shared Function usuarioIdentificar(ByVal p_nombreUsuario As String, ByVal p_contrasenna As String) As Hashtable
        Dim usuario As Usuario

        usuario = MultiUsuario.identificar(p_nombreUsuario, Utils.encriptar(p_contrasenna))

        If usuario Is Nothing Then
            Throw New Exception("El nombre de usuario y contraseña no coinciden.")
        End If

        g_usuario = usuario

        Return usuario.toHashtable()
    End Function

    ''' <summary>
    ''' Cierra la sesión de un usuario.
    ''' </summary>
    ''' <remarks>Creado por: Elías Baldioceda, Fecha: 20/06/2010, Modificado: 20/06/2010</remarks>
    Public Shared Sub usuarioCerrarSesion()
        If Not g_usuario Is Nothing Then
            g_usuario = Nothing
        End If
    End Sub

    ''' <summary>
    ''' Devuelve todos los roles del sistema.
    ''' </summary>
    ''' <returns>Todos los roles.</returns>
    ''' <remarks>Creado por: Elías Baldioceda, Fecha: 20/06/2010, Modificado: 20/06/2010</remarks>
    Public Shared Function rolBuscar() As List(Of Hashtable)
        Return MultiRol.buscar()
    End Function

    ''' <summary>
    ''' Obtiene todos los departamentos.
    ''' </summary>
    ''' <returns>Datos de todos los departamentos.</returns>
    ''' <remarks>Creado por: Elías Baldioceda, Fecha: 27/06/2010, Modificado: 27/06/2010</remarks>
    Public Shared Function departamentosTodos() As List(Of Hashtable)
        Dim departamentos As New List(Of Hashtable)

        For Each departamento As Departamento In MultiDepartamento.buscar("", "")
            departamentos.Add(departamento.toHashtable)
        Next

        Return departamentos
    End Function
#End Region

#Region "David"
    Public Shared Function usuarioObtenerCurriculo(ByVal p_identificacion As String) As Word.Document
        Return MultiUsuario.obtenerCurriculo(p_identificacion)
    End Function
#End Region

#Region "Roberto Fiatt"
    ''' <summary>
    ''' Consulta los puestos
    ''' </summary>
    ''' <param name="p_codigoDepartamento">Codigo del Departamento.</param>
    ''' <returns>Lista con los datos de los puestos del departamento.</returns>
    ''' <remarks>Creado Por: Roberto Fiatt, Fecha: 27/06/2010, Modificado: 27/06/2010</remarks>
    Public Shared Function listarPuestosPorDepartamento(ByVal p_codigoDepartamento As Integer) As List(Of Hashtable)
        Dim listaNiveles As List(Of Nivel)
        Dim listaPuestosDeNivel As List(Of Puesto)
        Dim listaDatos As New List(Of Hashtable)

        listaNiveles = consultarNivelesPorDepartamento(p_codigoDepartamento)

        For Each nivel As Nivel In listaNiveles
            listaPuestosDeNivel = MultiPuesto.consultarPuestosPorNivel(nivel.codigo())

            For Each puesto As Puesto In listaPuestosDeNivel
                listaDatos.Add(puestoToHash(puesto))
            Next
        Next

        Return listaDatos
    End Function

    ''' <summary>
    ''' Consultar los niveles de una departamento
    ''' </summary>
    ''' <param name="p_codigoDepartamento">Codigo del departamento.</param>
    ''' <returns>Lista con los niveles de un departamento.</returns>
    ''' <remarks>Creado Por: Roberto Fiatt, Fecha: 27/06/2010, Modificado: 27/06/2010</remarks>
    Public Shared Function consultarNivelesPorDepartamento(ByVal p_codigoDepartamento As Integer) As List(Of Nivel)
        Dim listaNiveles As New List(Of Nivel)
        listaNiveles = MultiNivel.listarPorDepartamento(p_codigoDepartamento)
        Return listaNiveles
    End Function

    ''' <summary>
    ''' Retornar los datos de codigo y nombre de puesto.
    ''' </summary>
    ''' <param name="puesto">Puesto.</param>
    ''' <returns>Hashtable con los datos del puesto.</returns>
    ''' <remarks>Creado Por: Roberto Fiatt, Fecha: 27/06/2010, Modificado: 27/06/2010</remarks>
    Private Shared Function puestoToHash(ByVal puesto As Puesto) As Hashtable
        Dim datosPuesto As New Hashtable

        datosPuesto.Add("codigo", puesto.codigo())
        datosPuesto.Add("nombre", puesto.nombre())

        Return datosPuesto
    End Function

    ''' <summary>
    ''' Modificar el puesto de un empleado.
    ''' </summary>
    ''' <param name="p_codigoEmpleado">Codigo Empleado.</param>
    ''' <param name="p_codigoPuesto">Codigo Puesto.</param>
    ''' <remarks>Creado Por: Roberto Fiatt, Fecha: 27/06/2010, Modificado: 27/06/2010</remarks>
    Public Shared Sub modificarPuestoAEmpleado(ByVal p_codigoEmpleado As String, ByVal p_codigoPuesto As Integer)
        MultiUsuario.modificarPuestoEmpleado(p_codigoEmpleado, p_codigoPuesto)
    End Sub
#End Region

#Region "Stephan Endres"
    Public Shared Function notificarCV(ByVal p_identificacion As String) As Boolean
        Return False
    End Function
#End Region

End Class
